package com.mobile.web.config.jwt;


import com.alibaba.fastjson.JSON;
import com.mobile.service.dto.RoleDTO;
import com.mobile.service.inter.system.FunctionService;
import com.mobile.service.inter.system.OrganizationService;
import com.mobile.service.inter.system.RoleService;
import com.mobile.service.inter.system.UserService;
import com.mobile.util.Const;
import com.mobile.util.PageData;
import com.mobile.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import com.mobile.util.JwtUtil ;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import redis.clients.jedis.Jedis;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @ClassName: JwtRealm
 * @Description: 自定义的身份验证与权限验证
 * @Date: 2022/11/24
 * @Author: wbr
 * @Version: 1.0
 */
@Slf4j
public class JwtRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    @Autowired
    FunctionService functionService;
    @Autowired
    RoleService roleService;
    @Autowired
    OrganizationService organizationService;
    private Logger logger = LogManager.getLogger(JwtRealm.class);
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }


    /**
     *  身份验证
     * @author wbr
     * @date 2022/11/25
     * @return: org.apache.shiro.authc.AuthenticationInfo
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        HttpServletResponse resp = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
        String credentials = (String) token.getCredentials();
        String userCode = null;
        PageData userPd = new PageData();
        RoleDTO userRole=new RoleDTO();
        Jedis jedis = RedisUtil.getJedis();

        try {
            boolean verify = JwtUtil.verify(credentials);
            if (!verify) {
                throw new AuthenticationException("Token校验不正确");
            }
            userCode = JwtUtil.getClaim(credentials, JwtUtil.ACCOUNT);


        } catch (Exception e) {
            logger.warn(e.getMessage());
            try {
                resp.sendError(401,e.getMessage());
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            return null;
//            throw new BusinessException(CommonResultStatus.TOKEN_CHECK_ERROR,e.getMessage());
        }

        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，不设置则使用默认的SimpleCredentialsMatcher
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userCode, //用户名
                credentials, //凭证
                getName()  //realm name
        );
        //判断是否首次登录需要添加redis信息
        if (!Optional.ofNullable(jedis.hget(Const.SESSION_USER, userCode)).isPresent()) {
            try {
                userPd = userService.getUserByCode(userCode);
                userRole = roleService.getRoleById((Integer) userPd.get("user_role"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 验证成功后，菜单权限及用户信息保存
            jedis.hset(Const.SESSION_USER,userCode, JSON.toJSONString(userPd));
            //放入用户名到session
            jedis.hset(Const.SESSION_USERNAME,userCode, userPd.getString("user_name"));

            //放入用户账号到session
            jedis.hset(Const.SESSION_USERCODE,userCode, userCode);
            //添加用户角色
            jedis.hset(Const.SESSION_USERROLE,userCode, userRole.getRoleCode());
        }

        jedis.close();
        return  authenticationInfo;
    }

    /**
     *  权限校验
     * @author wbr
     * @date 2022/11/25
     * @param principals:
     * @return: org.apache.shiro.authz.AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String currentLoginName = principals.toString();
        List<String> userRoles = new ArrayList<String>();
        List<String> rfaButtonFunctionList = new ArrayList<String>();
        Jedis jedis = RedisUtil.getJedis();
        // 获取当前登录用户的详细信息
        PageData userPd;
        try {
            userPd = userService.getUserByCode(currentLoginName);
            PageData rfaPd = new PageData();

            if (userPd != null) {
                //获取当前用户下拥有的所有权限信息
                rfaPd.put("userCode", currentLoginName);
                userRoles.add(userPd.get("user_role").toString());
                rfaButtonFunctionList = functionService.getAuthDataByUserCode(rfaPd);

            } else {
                throw new AuthorizationException();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        logger.info("MySystemRealm.class->获取角色：" + userRoles.size());
        logger.info("MySystemRealm.class->获取权限：" + rfaButtonFunctionList.size());
        //为当前用户设置角色和权限
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(userRoles);
        authorizationInfo.addStringPermissions(rfaButtonFunctionList);
        //当前登录账号对应的菜单权限放入redis中
        jedis.hset( Const.SESSION_menuList,currentLoginName, JSON.toJSONString(rfaButtonFunctionList));
        jedis.close();
        return authorizationInfo;
    }

}
